﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace DCT.CodeBox.EventTrigger.Codes
{
    public class EventProxy<TArgument> : IDisposable
    {
        private object target;
        private string eventName;
        EventTrigger<TArgument> trigger;

        public EventProxy(object target, string eventName)
        {
            this.target = target;
            this.eventName = eventName;

            if (target == null) {
                throw new NullReferenceException("target is null");
            }
            if (string.IsNullOrWhiteSpace(eventName))
            {
                throw new NullReferenceException("eventName is null");
            }
        }

        private void Attatch() {
            Type targetType = this.target.GetType();
            EventInfo eventInfo = targetType.GetEvent(this.eventName);
            Type eventHandlerType = eventInfo.EventHandlerType;

            trigger = EventTrigger<TArgument>.CreateInstance();
            //eventInfo.AddEventHandler(target, 
            
        }

        private void Detatch()
        {
        }
        
        public void Dispose()
        {
            Detatch();
        }

    }

    public class TestClass {

        public static Type CreateType2() {
            AssemblyName assName = new AssemblyName("tmpAss");
            AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.RunAndSave);
            //动态创建模块
            ModuleBuilder mb = dynamicAssembly.DefineDynamicModule(assName.Name, assName.Name + ".dll");
            //动态创建类MyClass
            TypeBuilder tb = mb.DefineType("MyClass", TypeAttributes.Public);

            //动态创建方法
            MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig;
            MethodBuilder myMethod = tb.DefineMethod("Add"
                , methodAttr
                , typeof(int)
                , new Type[] { typeof(int), typeof(int) });
            /*
             生成方法
             public static int Add(int x, int y){
                int[] arr = new arr[2];
                arr[0] = x;
                arr[1] = y;
                int result = AddMany(arr);
                return result;
             }
             */
            //生成指令
            ILGenerator il = myMethod.GetILGenerator();

            LocalBuilder locArr = il.DeclareLocal(typeof(int[]));
            LocalBuilder locResult = il.DeclareLocal(typeof(int));
            il.Emit(OpCodes.Nop);

            //int[] arr = new arr[2];
            il.Emit(OpCodes.Ldc_I4_2);
            il.Emit(OpCodes.Newarr, typeof(int));
            il.Emit(OpCodes.Stloc_0);
            //arr[0] = x;
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stelem_I4);
            //arr[1] = y;
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Stelem_I4);
            //int result = AddMany(arr);
            il.Emit(OpCodes.Ldloc_0);
            MethodInfo addManyMethod = typeof(TestClass).GetMethod("AddMany"
                , BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static);
            il.Emit(OpCodes.Call, addManyMethod);
            il.Emit(OpCodes.Stloc_1);
            il.Emit(OpCodes.Ldloc_1);
            il.Emit(OpCodes.Ret);

            Type targetType = tb.CreateType();

            dynamicAssembly.Save(assName.Name + ".dll");
            return targetType;
        }

        public static int Add(int x, int y)
        {
            int[] arr = new int[2];
            arr[0] = x;
            arr[1] = y;
            int result = AddMany(arr);
            return result;
        }

        public static int AddMany(int[] arr) {
            int result = 0;
            foreach (var item in arr)
            {
                result += item;
            }
            return result;
        }

        public static void CreateType() {
            //动态创建程序集
            AssemblyName DemoName = new AssemblyName("DynamicAssembly");
            AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(DemoName, AssemblyBuilderAccess.RunAndSave);
            //动态创建模块
            ModuleBuilder mb = dynamicAssembly.DefineDynamicModule(DemoName.Name, DemoName.Name + ".dll");
            //动态创建类MyClass
            TypeBuilder tb = mb.DefineType("MyClass", TypeAttributes.Public);
            //动态创建字段
            FieldBuilder fb = tb.DefineField("f", typeof(System.String), FieldAttributes.Private);
            //动态创建构造函数
            Type[] clorType = new Type[] { typeof(System.String) };
            ConstructorBuilder cb1 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, clorType);
            //生成指令
            ILGenerator ilg = cb1.GetILGenerator();//生成 Microsoft 中间语言 (MSIL) 指令
            ilg.Emit(OpCodes.Ldarg_0);
            ilg.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
            ilg.Emit(OpCodes.Ldarg_0);
            ilg.Emit(OpCodes.Ldarg_1);
            ilg.Emit(OpCodes.Stfld, fb);
            ilg.Emit(OpCodes.Ret);
            //动态创建属性
            PropertyBuilder pb = tb.DefineProperty("MyProperty", PropertyAttributes.HasDefault, typeof(string), null);
            //动态创建方法
            MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName;
            MethodBuilder myMethod = tb.DefineMethod("get_Property", getSetAttr, typeof(string), Type.EmptyTypes);
            //生成指令
            ILGenerator numberGetIL = myMethod.GetILGenerator();
            numberGetIL.Emit(OpCodes.Ldarg_0);
            numberGetIL.Emit(OpCodes.Ldfld, fb);
            numberGetIL.Emit(OpCodes.Ret);

            tb.CreateType();
            //保存动态创建的程序集
            dynamicAssembly.Save(DemoName.Name + ".dll");

        }

        public static void Run() {
            Type type = CreateType2();
            MethodInfo m = type.GetMethod("Add", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static);
            object result = m.Invoke(null, new object[] { 2, 4 });
            Console.WriteLine(result);
        }
    }    
}

namespace TFM {
    public interface IResume { string Source { get; } }
    public class CjobResume : IResume { public string Source { get { return "CJOL"; } } }
    public class ZhaoPinResume : IResume { public string Source { get { return "Zhaopin"; } } }
    public class The51jobResume : IResume { public string Source { get { return "51Job"; } } }

    public class ResumeFactory {
        /// <summary>
        /// 创建实例的方法
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public static IResume Create(string typeName) {
            IResume resume = null;
            Type type = Type.GetType(typeName, false);
            if (type != null) {
                resume = Activator.CreateInstance(type) as IResume;
            }
            return resume;
        }

        public static void Run() {
            IResume resume = null;
            resume = Create("TFM.CjobResume");
            Console.WriteLine(resume.Source);       //CJOL
            resume = Create("TFM.ZhaoPinResume");
            Console.WriteLine(resume.Source);       //Zhaopin
            resume = Create("TFM.The51jobResume");
            Console.WriteLine(resume.Source);       //51Job
        }
    }
}
